Temperature Plots (all venues)#
Choose your venue from the dropdown menu. Then you can use the slider below the plot to explore your data. You can make the data “window” as small or as large as you want, and also slide the entire window to the left or the right. You can also choose a window size to be an hour, a day, a week, or a year using the buttons above the plot.
These plots work best on a large screen. If you can’t see the right edge of the plot, try using your browser zoom features to get the full plot. On many browsers, ctrl-+ (holding the control button and the + sign at the same time) will zoom in and ctrl-minus (the control button with the minus sign) will zoom out. Zooming is also available from the browser menus. We are looking at what we can do to facilitate use on other screen sizes.
Bug work-around
If you change venue sometimes you will get the new data superimposed on the old data rather than replacing it. If this happens, reload the page.
Show code cell content
# Imports
import ipywidgets as widgets
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from IPython.display import display
import datetime
# First, set up the data.
def timezoneString(hoursAhead):
if (hoursAhead==0):
return "GMT"
elif (hoursAhead==1):
return "BST"
else:
return ("time error")
# Get the possible data venues
venuekeysfile = "venue-keys.csv"
dfVenueKeys = pd.read_csv(venuekeysfile)
dfVenueKeys = dfVenueKeys.dropna(subset=['channel_id'])
# Load all data from all files.
dfCollatedDataSet = pd.DataFrame() #columns=['timestamp', 'entry_id', 'temperature', 'rh', 'voltage', 'venue_id'])
for index, venueSensorDetails in dfVenueKeys.iterrows():
sensorMacOfSelection = venueSensorDetails['sensor_MAC']
venueOfSelection = str(venueSensorDetails['venue_id'])
try:
dfTempDataSet = pd.read_csv('deviceData/'+ "venue_" + venueOfSelection + "_with_device_" + sensorMacOfSelection + '.csv' )
# eliminate worst of rogue data
dfTempDataSet = dfTempDataSet[(dfTempDataSet.temperature <= 100)]
dfTempDataSet = dfTempDataSet[(dfTempDataSet.temperature > -10)]
# Plotly can't mix timezones/summer and winter time in the same trace. The workaround is loosely based on
# https://github.com/plotly/plotly.py/issues/2872 contribution by CalebCarroll, 11 November 2021.
# TIMESTAMP as stored in the csv file is UTC - usual best practice.
# HOVER_TIMESTAMP is the datetime as in the locale, which when formatted with
# %z will end in +0000 or +0100 for UTC + 0 hours (GMT) or UTC + 1 hour (BST). We use this timestamp to
# determine the OFFSET number of hours and use this for two things:
# (1) to print the appropriate TIMEZONESTRING as hover text (GMT or BST) by changing the hovertemplate.
# (2) to calculate an X_TIMESTAMP for use on the x axis - which is an expression of local time. This
# is done just by adding the correct timedelta to the original timestamp. X_TIMESTAMP is then
# treated as naive, although logically it is still UTC. It is only used in the UI for display,
# so that's OK.
## in theory, it's possible to completely control the hovertemplate so we should be able to get the timezone
## together with the date. In practice, this appears to be difficult to get right with graph_objects.
dfTempDataSet['hover_timestamp'] = pd.to_datetime(dfTempDataSet['timestamp']).dt.tz_convert("Europe/London")
dfTempDataSet['offset'] = pd.to_numeric(dfTempDataSet['hover_timestamp'].dt.strftime("%z").str[2])
dfTempDataSet['timezoneString'] = dfTempDataSet['offset'].map(lambda x: (timezoneString(x)))
dfTempDataSet['x_timestamp'] = dfTempDataSet['hover_timestamp'] + dfTempDataSet['offset'].map(lambda x: pd.Timedelta(x,"h"))
# Add the venue_id as a column so we can shove all the data in one big dataframe.
dfTempDataSet['venue_id'] = venueSensorDetails['venue_id']
## help performance - we dropped columns we don't need. Standalone data has original-timestamp for a few venues and always
## has a useless entry_id.
### decide later whether to drop location - we may want to use it in future, if people get their location diaries set up.
dfTempDataSet = dfTempDataSet.drop(["timestamp","original-timestamp","hover_timestamp","entry_id","offset"], axis=1, errors="ignore")
#dfCollatedDataSet = dfCollatedDataSet.append(dfTempDataSet, ignore_index=True)
dfCollatedDataSet = pd.concat([dfCollatedDataSet, dfTempDataSet])
dfCollatedDataSet['x_timestamp'] = pd.to_datetime(dfCollatedDataSet['x_timestamp'])
print('Loading data for venue: ', venueSensorDetails['venue_id'])
except:
print("Couldn't load data for venue ", venueSensorDetails['venue_id'])
print('Check')
dfCollatedDataSet.sample(6)
Loading data for venue: 1
Loading data for venue: 2
Loading data for venue: 2h
Loading data for venue: 3
Loading data for venue: 5
Loading data for venue: 6
Loading data for venue: 7
Loading data for venue: 8
Loading data for venue: 9
Loading data for venue: 10
Loading data for venue: 11
Loading data for venue: 12
Loading data for venue: 13
Loading data for venue: 15
Loading data for venue: 16
Loading data for venue: 17
Loading data for venue: 18
Loading data for venue: 19
Loading data for venue: 20
Loading data for venue: 21
Loading data for venue: 22
Loading data for venue: 23
Loading data for venue: 24
Couldn't load data for venue 25
Loading data for venue: 26
Loading data for venue: 28
Loading data for venue: 29
Loading data for venue: 31
Loading data for venue: 33
Loading data for venue: 36
Loading data for venue: 40
Loading data for venue: 97lh
Loading data for venue: 97s
Loading data for venue: 98
Loading data for venue: 99
Check
| temperature | rh | voltage | timezoneString | x_timestamp | venue_id | location | voltage2023-04-06T09:26:54Z | 1 | Unnamed: 6 | Unnamed: 7 | 1.1 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 12204 | 8.0 | 79.0 | NaN | GMT | 2022-12-19 20:28:48+00:00 | 7 | NaN | NaN | NaN | NaN | NaN | NaN |
| 2978 | 10.0 | 55.0 | NaN | GMT | 2023-01-28 20:02:00+00:00 | 97s | NaN | NaN | NaN | NaN | NaN | NaN |
| 32627 | 16.0 | 63.0 | NaN | GMT | 2023-03-06 20:26:14+00:00 | 7 | NaN | NaN | NaN | NaN | NaN | NaN |
| 43156 | 15.0 | 45.0 | NaN | GMT | 2023-03-09 03:52:19+00:00 | 11 | NaN | NaN | NaN | NaN | NaN | NaN |
| 20342 | 11.0 | 67.0 | NaN | GMT | 2023-01-17 18:21:10+00:00 | 7 | NaN | NaN | NaN | NaN | NaN | NaN |
| 23658 | 15.0 | 74.0 | NaN | GMT | 2023-01-29 12:22:17+00:00 | 7 | NaN | NaN | NaN | NaN | NaN | NaN |
Show code cell content
# get the basic figure together.
# FigureWidgets allow a figure to be dynamically updated. We use that for two things: letting users
# change the data view with a range slider, and lettings users choose a different venue to look at from
# a dropdown menu.
## Can't figure out how to get the data for the first venue to show. Odd that it gets the x_axis right
## but not the y_axis (even though that never changes) and doesn't show the trace. Not worth chasing since
## the dropdown will get retired soon - it's too much data to load at once.
#give user option to select their venue.
venueDropdown = widgets.Dropdown(
options=dfVenueKeys['venue_id'],
value=dfVenueKeys['venue_id'][0],
description='Venue ID:',
disabled=False,
)
container = widgets.HBox(children=[venueDropdown])
print(venueDropdown.value)
# struggling to control the hover text properly - In Plotly express hover_name
# property to declare what goes at the top, but that doesn't work here; not allowed.
trace0 = go.Scatter(#customdata=dfCollatedDataSet[dfCollatedDataSet['venue_id'] == 0],
y=dfCollatedDataSet[dfCollatedDataSet['venue_id']==dfVenueKeys['venue_id'][0]] ['temperature'],
x = dfCollatedDataSet[dfCollatedDataSet['venue_id']==dfVenueKeys['venue_id'][0]]['x_timestamp'],
mode='lines',
line_color="blue",
line_width = 1,
customdata=dfCollatedDataSet[dfCollatedDataSet['venue_id']==dfVenueKeys['venue_id'][0]]['timezoneString'],
hovertemplate='%{y}<br>%{customdata}',
showlegend=False,
name='Temperature',
)
g = go.FigureWidget(data=trace0,
layout = go.Layout(
yaxis=dict(range=[0,30])
))
print("Job Done")
1
Job Done
Show code cell source
# Make it dynamic.
updatemenu = []
buttons = []
# button with one option for each dataframe
for index, venue in dfVenueKeys.iterrows():
buttons.append(dict(method='update',
label='Venue ' + str(venue['venue_id']),
visible=True,
args=[{'y':[dfCollatedDataSet[dfCollatedDataSet['venue_id']==venue['venue_id']]['temperature'].values],
'x':[dfCollatedDataSet[dfCollatedDataSet['venue_id']==venue['venue_id']]['x_timestamp'].values],
'customdata':[dfCollatedDataSet[dfCollatedDataSet['venue_id']==venue['venue_id']]['timezoneString'].values],
'type':'scatter',
},
{
'title.text': 'Temperature for Venue = ' + str(venue['venue_id']),
'title.font.color': 'green',
'yaxis.range': [0,30],
'yaxis.title.text': 'Temperature',
'xaxis.title.text': 'local time (includes daylight savings correction)'
},
],
)
)
# some adjustments to the updatemenus
updatemenu = []
your_menu = dict()
updatemenu.append(your_menu)
updatemenu[0]['buttons'] = buttons
updatemenu[0]['direction'] = 'down'
updatemenu[0]['showactive'] = True
#updatemenu[0]['active'] = 0
fig = go.Figure(g)
# this works for plotly express but not for graph_objects?
#fig.update_traces(hovertemplate=None)
#fig.update_traces(hovertemplate='%{x:"%Y-%m-%d %H:%M %Z"}')
# add dropdown menus to the figure
fig.update_layout(showlegend=True,
updatemenus=updatemenu,
autosize = True,
title= "Please select a venue to see your data.",
width=1000,
height=500,
)
fig.update_layout(
hovermode='x unified',
hoverlabel=dict(
bgcolor="white",
# font_size=16,
font_family="Rockwell"
)
)
# Add range slider
fig.update_layout(
xaxis=dict(
rangeselector=dict(
buttons=list([
dict(
label="All",
step="all"
),
dict(count=1,
label="Hour",
step="hour",
stepmode="todate"),
dict(count=1,
label="Day",
step="day",
stepmode="backward"),
dict(count=7,
label="Week",
step="day",
stepmode="backward"),
dict(count=1,
label="Year",
step="year",
stepmode="backward")
])
),
rangeslider=dict(
visible=True,
),
type="date"
)
)
#print("plotly express hovertemplate:", fig.data[0].hovertemplate)
#fig.update_xaxes(
# tickformat="%Y-%m-%d %H:%M" # date format
#)
#fig.update_yaxes(range=[50, 60])
#fig.add_hline(y=16, annotation_text='16C - usual minimum for children', annotation_font_color="blue", line_color='red', layer='above', line_dash='dash')
# fig.update_yaxes(range = [-5, dfCollatedDataSet['temperature'].max()+5])
fig.show()